package apralms

import org.springframework.dao.DataIntegrityViolationException

class SchemeController {

    static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

    def index() {
        redirect(action: "list", params: params)
    }

    def list() {
        params.max = Math.min(params.max ? params.int('max') : 10, 100)
        [schemeInstanceList: Scheme.list(params), schemeInstanceTotal: Scheme.count()]
    }

    def create() {
        [schemeInstance: new Scheme(params)]
    }

    def save() {
        def schemeInstance = new Scheme(params)

        if (!schemeInstance.save(flush: true)) {
            render(view: "create", model: [schemeInstance: schemeInstance])
            return
        }

        createIndex(schemeInstance)
        createFact(schemeInstance)

        flash.message = message(code: 'default.created.message', args: [message(code: 'scheme.label', default: 'Scheme'), schemeInstance.id])
        redirect(action: "show", id: schemeInstance.id)
    }

    def show() {
        def schemeInstance = Scheme.get(params.id)
        if (!schemeInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "list")
            return
        }

        [schemeInstance: schemeInstance]
    }

    def edit() {
        def schemeInstance = Scheme.get(params.id)
        if (!schemeInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "list")
            return
        }

        [schemeInstance: schemeInstance]
    }

    def update() {
        def schemeInstance = Scheme.get(params.id)
        if (!schemeInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "list")
            return
        }

        if (params.version) {
            def version = params.version.toLong()
            if (schemeInstance.version > version) {
                schemeInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
                        [message(code: 'scheme.label', default: 'Scheme')] as Object[],
                        "Another user has updated this Scheme while you were editing")
                render(view: "edit", model: [schemeInstance: schemeInstance])
                return
            }
        }

        schemeInstance.properties = params

        if (!schemeInstance.save(flush: true)) {
            render(view: "edit", model: [schemeInstance: schemeInstance])
            return
        }

        flash.message = message(code: 'default.updated.message', args: [message(code: 'scheme.label', default: 'Scheme'), schemeInstance.id])
        redirect(action: "show", id: schemeInstance.id)
    }

    def delete() {
        def schemeInstance = Scheme.get(params.id)
        if (!schemeInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "list")
            return
        }

        try {
            schemeInstance.delete(flush: true)
            flash.message = message(code: 'default.deleted.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "list")
        }
        catch (DataIntegrityViolationException e) {
            flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "show", id: params.id)
        }
    }

    def calculate() {
        def schemeInstance = Scheme.get(params.id)
        if (!schemeInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
            redirect(action: "list")
            return
        }

        calculateIndex(schemeInstance)
        flash.message = message(code: 'default.calculated.message', args: [message(code: 'scheme.label', default: 'Scheme'), params.id])
        redirect(action: "show", id: schemeInstance.id)
    }

    /**
     * 生成指标体系
     * @param schemeInstance
     * @return
     */
    def createIndex(Scheme schemeInstance) {
        def projectInstance = schemeInstance.project

        // 项目指标
        projectInstance.classParas.split(",").each { paraName ->
            def parameterInstance = Parameter.findByName(paraName)
            if (parameterInstance != null) {
                def projectIndexInstance = new ProjectIndex(
                        code: parameterInstance.code,
                        name: parameterInstance.name,
                        project: projectInstance,
                        scheme: schemeInstance,
                        parameter: parameterInstance)
                projectIndexInstance.save()
            }
        }

        // 系统指标
        projectInstance.systems.each { systemInstance ->
            systemInstance.classParas.split(",").each { paraName ->
                def parameterInstance = Parameter.findByName(paraName)
                if (parameterInstance != null) {
                    def systemIndexInstance = new SystemIndex(
                            code: parameterInstance.code,
                            name: parameterInstance.name,
                            system: systemInstance,
                            scheme: schemeInstance,
                            parameter: parameterInstance)
                    systemIndexInstance.save()
                }
            }
        }

        // 产品指标
        projectInstance.products.each { productInstance ->
            productInstance.classParas.split(",").each { paraName ->
                def parameterInstance = Parameter.findByName(paraName)
                if (parameterInstance != null) {
                    def productIndexInstance = new ProductIndex(
                            code: parameterInstance.code,
                            name: parameterInstance.name,
                            product: productInstance,
                            scheme: schemeInstance,
                            parameter: parameterInstance)
                    productIndexInstance.save()
                }
            }
        }
    }

    /**
     * 生成计算因子
     * @param schemeInstance
     * @return
     */
    def createFact(Scheme schemeInstance) {
        def projectInstance = schemeInstance.project

        // 系统因子
        projectInstance.systems.each {
            def fact = new SystemFact(system: it, scheme: schemeInstance)
            fact.save()
        }

        // 产品因子
        projectInstance.products.each {
            def fact = new ProductFact(product: it, scheme: schemeInstance)
            fact.save()
        }
    }

    /**
     * 方案指标值计算
     * @param schemeInstance
     * @return
     */
    def calculateIndex(Scheme schemeInstance) {
        calculateSystemIndex(schemeInstance)

        schemeInstance.systemIndexes.each {
            calculateProductIndex(schemeInstance, it)
        }
    }

    /**
     * 产品指标值计算
     * @param schemeInstance
     * @param systemIndexInstance
     * @return
     */
    def calculateProductIndex(Scheme schemeInstance, SystemIndex systemIndexInstance) {
        def knownProductIndexes = [], unknownProductIndexes = []
        def targetList = [], limitList = [] // 已知值列表
        def readyTarget = 0, readyLimit = 0
        def targetValue = 0, limitValue = 0

        schemeInstance.productIndexes.each {
            if (it.parameter == systemIndexInstance.parameter) {
                if (it.known) {
                    knownProductIndexes << it
                    targetList << it.targetValue
                    limitList << it.limitValue
                } else {
                    unknownProductIndexes << it
                }
            }
        }

        // 计算可分配值
        readyTarget = Calculator.getAdjust(systemIndexInstance.targetValue, systemIndexInstance.spareValue)
        readyLimit = Calculator.getAdjust(systemIndexInstance.limitValue, systemIndexInstance.spareValue)

        readyTarget = Calculator.getReadyForAllot(readyTarget, targetList)
        readyLimit = Calculator.getReadyForAllot(readyLimit, limitList)

        // 去除已知系统指标值，计算分配值
        // 等分配法
        if (schemeInstance.calMode2 == '1') {
            targetValue = Calculator.getAllotByAverage(readyTarget, unknownProductIndexes.size())
            limitValue = Calculator.getAllotByAverage(readyLimit, unknownProductIndexes.size())

            // 将预分配值分配给下属系统
            unknownProductIndexes.each {
                if (it.parameter == systemIndexInstance.parameter) {
                    it.targetValue = targetValue
                    it.limitValue = limitValue
                    it.save()
                }
            }
        }

        // 比例组合分配法
        if (schemeInstance.calMode2 == '2') {
            def failureRatioSum = 0
            unknownProductIndexes.each {
                def systemFact = SystemFact.findBySchemeAndSystem(schemeInstance, it.system)
                failureRatioSum += systemFact.failRatio
            }

            unknownProductIndexes.each {
                def systemFact = SystemFact.findBySchemeAndSystem(schemeInstance, it.system)
                it.targetValue = Calculator.getAllotByScale(readyTarget, failureRatioSum, systemFact.failRatio)
                it.limitValue = Calculator.getAllotByScale(readyLimit, failureRatioSum, systemFact.failRatio)
                it.save()
            }
        }

        // 评分分配法
        if (schemeInstance.calMode2 == '3') {
            def multiplyValueSum = 0
            unknownProductIndexes.each {
                def score = Score.findBySystem(it.system)
                multiplyValueSum += score.multiplyValue
            }

            def factor = 0
            unknownSystemIndexes.each {
                def score = Score.findBySystem(it.system)
                it.targetValue = Calculator.getAllotByGrade(readyTarget, score.multiplyValue / multiplyValueSum)
                it.limitValue = Calculator.getAllotByGrade(readyLimit, score.multiplyValue / multiplyValueSum)
                it.save()
            }
        }
    }

    /**
     * 系统指标值计算
     * @param schemeInstance
     * @return
     */
    def calculateSystemIndex(Scheme schemeInstance) {
        def ProjectIndex projectIndexInstance

        // 获取已知项目指标
        schemeInstance.projectIndexes.each {
            if (it.known) {
                projectIndexInstance = it
            }
        }
        if (!projectIndexInstance) return

        def knownSystemIndexes = [], unknownSystemIndexes = []
        def targetList = [], limitList = [] // 已知值列表
        def readyTarget = 0, readyLimit = 0
        def targetValue = 0, limitValue = 0

        schemeInstance.systemIndexes.each {
            if (it.parameter == projectIndexInstance.parameter) {
                if (it.known) {
                    knownSystemIndexes << it
                    targetList << it.targetValue
                    limitList << it.limitValue
                } else {
                    unknownSystemIndexes << it
                }
            }
        }

        // 计算可分配值
        readyTarget = Calculator.getAdjust(projectIndexInstance.targetValue, projectIndexInstance.spareValue)
        readyLimit = Calculator.getAdjust(projectIndexInstance.limitValue, projectIndexInstance.spareValue)

        readyTarget = Calculator.getReadyForAllot(readyTarget, targetList)
        readyLimit = Calculator.getReadyForAllot(readyLimit, limitList)

        // 去除已知系统指标值，计算分配值
        // 等分配法
        if (schemeInstance.calMode1 == '1') {
            targetValue = Calculator.getAllotByAverage(readyTarget, unknownSystemIndexes.size())
            limitValue = Calculator.getAllotByAverage(readyLimit, unknownSystemIndexes.size())

            // 将预分配值分配给下属系统
            unknownSystemIndexes.each {
                if (it.parameter == projectIndexInstance.parameter) {
                    it.targetValue = targetValue
                    it.limitValue = limitValue
                    it.save()
                }
            }
        }

        // 比例组合分配法
        if (schemeInstance.calMode1 == '2') {
            def failureRatioSum = 0
            unknownSystemIndexes.each {
                def systemFact = SystemFact.findBySchemeAndSystem(schemeInstance, it.system)
                failureRatioSum += systemFact.failRatio
            }

            unknownSystemIndexes.each {
                def systemFact = SystemFact.findBySchemeAndSystem(schemeInstance, it.system)
                it.targetValue = Calculator.getAllotByScale(readyTarget, failureRatioSum, systemFact.failRatio)
                it.limitValue = Calculator.getAllotByScale(readyLimit, failureRatioSum, systemFact.failRatio)
                it.save()
            }
        }

        // 评分分配法
        if (schemeInstance.calMode1 == '3') {
            def multiplyValueSum = 0
            unknownSystemIndexes.each {
                def score = Score.findBySystem(it.system)
                multiplyValueSum += score.multiplyValue
            }

            def factor = 0
            unknownSystemIndexes.each {
                def score = Score.findBySystem(it.system)
                it.targetValue = Calculator.getAllotByGrade(readyTarget, score.multiplyValue / multiplyValueSum)
                it.limitValue = Calculator.getAllotByGrade(readyLimit, score.multiplyValue / multiplyValueSum)
                it.save()
            }
        }
    }
}
